﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Input;
using System.Windows.Threading;
using AG.Infrastructure.CabSupport;
using Microsoft.Practices.Composite.Presentation.Commands;
using AG.Infrastructure.Utility;

namespace VocabCards
{
    public class CardCreatorVM : ViewModelBase
    {
        private readonly Dispatcher _dispatcher;
        public ICommand CreateCardsCommand { get; private set; }
        public ObservableCollection<Card> Cards { get; private set; }

        [Obsolete("for testing only", false)]
        public CardCreatorVM()
            : this(null)
        {
        }

        public CardCreatorVM(Dispatcher dispatcher)
        {
            _dispatcher = dispatcher;


            Cards = new ObservableCollection<Card>();
            CardHeight = 350;
            CardWidth = 250;

            CreateCardsCommand = new DelegateCommand<string>(obj => CreateCards());
            WordsInput = string.Empty;
            CreateDemoCard();
        }

        void CreatePleaseWaitCard()
        {
            Cards.Clear();

            var card = new Card()
                           {
                               Height = CardHeight,
                               Width = CardWidth
                           }
                ;

            card.Word = new WordProperties()
                            {
                                Word = "Please Wait",
                                Denormalize = true
                            };

            card.Word.Definitions.Add(
                new Definition()
                    {
                        PartOfSpeech = "request",
                        Synonyms = new List<string>() { "Patience", "Hold On", "One Moment Please" },
                        Def =
                            "asks to pause before taking action"
                    });

            card.Suit = _cardAttributes.Heart;
            card.Rank = "K";
            card.Red = _cardAttributes.RedSuits.Contains(card.Suit);

            Cards.Add(card);
        }

        void CreateDemoCard()
        {
            var card = new Card()
                           {
                               Height = CardHeight,
                               Width = CardWidth
                           }
                ;

            card.Word = new WordProperties()
                            {
                                Word = "Word War",
                                Denormalize = true
                            };

            card.Word.Definitions.Add(
                  new Definition()
                  {
                      PartOfSpeech = "noun",
                      Synonyms = new List<string>() { "Game", "Card Game", "Vocabulary Game" },
                      Def = "a fun game using standard playing cards with vocabulary words and definitions that helps build vocabulary"
                  });

            card.Suit = _cardAttributes.Heart;
            card.Rank = "A";
            card.Red = _cardAttributes.RedSuits.Contains(card.Suit);


            Cards.Add(card);


            card = new Card()
            {
                Height = CardHeight,
                Width = CardWidth
            }
;

            card.Word = new WordProperties()
                            {
                                Word = "Word War Card",
                                Denormalize = true
                            };

            card.Word.Definitions.Add(
                  new Definition()
                  {
                      PartOfSpeech = "noun",
                      Synonyms = new List<string>() { "VocabCard", "FlashCard", "StudyCard" },
                      Def = "a playing card used in a fun game that builds vocabulary"
                  });

            card.Suit = _cardAttributes.Diamond;
            card.Rank = "A";
            card.Red = _cardAttributes.RedSuits.Contains(card.Suit);

            Cards.Add(card);

        }




        string _wordsInput;

        public string WordsInput
        {
            get { return _wordsInput; }
            set
            {
                CheckPropertyChanged("WordsInput", ref _wordsInput, value);
            }
        }


        static readonly CardAttributes _cardAttributes = new CardAttributes();

        public class CardAttributes
        {
            public string[] Ranks { get { return "2 3 4 5 6 7 8 9 10 J Q K A".Split(' '); } }
            public string[] Suits { get { return "♥ ♦ ♣ ♠".Split(' '); } }
            public string[] RedSuits { get { return "♥ ♦".Split(' '); } }

            public string Diamond
            {
                get { return "♦"; }
            }
            public string Spade
            {
                get { return "♠"; }
            }
            public string Club
            {
                get { return "♣"; }
            }
            public string Heart
            {
                get { return "♥"; }
            }
        }



        void CreateCards()
        {
            //split on comma and newline

            var words = WordsInput.Trim().Split(new char[] { '\r', '\t', '\n', ',' })
                .Where(w => w.Trim() != "").ToArray();


            if (words.Length != 0)
            {

                var wc = new ObservableCollection<string>();
                words.ForEach(w =>
                                  {
                                      if (wc.Count < 54)
                                      {
                                          wc.Add(w);
                                      }
                                  });

                var client = new WordService.WordsClient();

                client.DefineWordsCompleted += (sender, args) =>
                      {
                          var t = new Thread(() => WordsDefined(args));
                          t.Start();
                      };

                client.DefineWordsAsync(wc);

                CreatePleaseWaitCard();

            }

        }



        bool _cardsAvailable;

        public bool CardsAvailable
        {
            get { return _cardsAvailable; }
            set
            {
                CheckPropertyChanged("CardsAvailable", ref _cardsAvailable, value);
            }
        }

        //todo:  show a count of cards created -- give some ui feedback there
        //fill in the arrays in the secondary thread
        //add cards on dispatcher thread after they've been calc'd 
        void WordsDefined(WordService.DefineWordsCompletedEventArgs e)
        {

            var words = e.Result;

            if (words == null || words.Count == 0)
            {
                //todo:  define a "no words found -- please try again"
                return;

            }
            
            var i = 0;
            var count = words.Count;

            if (count == 0) return;

            var _processedWords = new List<WordProperties>();

            _cardAttributes.Suits.ForEach(
                suit =>
                    _cardAttributes.Ranks.ForEach(
                    rank =>
                    {
                        var w = words[i % count];
                        var c = new Card() { Rank = rank, Suit = suit, Word = w };
                        c.Red = _cardAttributes.RedSuits.Contains(c.Suit);
                        c.Height = CardHeight;
                        c.Width = CardWidth;


                        _dispatcher.BeginInvoke(() => Cards.Add(c));

                        //let the card display
                        //Thread.Sleep(150);

                        if (!_processedWords.Contains(w))
                        {
                            w.Denormalize = true;
                            w.ResetSynAnt(MaxSynAnt);
                            _processedWords.Add(w);
                        }
                        i++;

                    }
                    )

                );

            _dispatcher.BeginInvoke(() =>
                                        {
                                            CardsAvailable = true;
                                            
                                            //remove the please wait
                                            Cards.RemoveAt(0);
                                        }
                );

            


        }

        /// <summary>
        /// a very unXAML function :(
        /// </summary>
        void SetHeightAndWidthOfCards()
        {
            foreach (var card in Cards)
            {
                card.Height = CardHeight;
                card.Width = CardWidth;
            }
        }

        int _cardHeight;

        public int CardHeight
        {
            get { return _cardHeight; }
            set
            {
                CheckPropertyChanged("CardHeight", ref _cardHeight, value);
                SetHeightAndWidthOfCards();
            }
        }

        int _cardWidth;

        public int CardWidth
        {
            get { return _cardWidth; }
            set
            {
                CheckPropertyChanged("CardWidth", ref _cardWidth, value);
                SetHeightAndWidthOfCards();
            }
        }




        int _maxSynAnt = 10;

        public int MaxSynAnt
        {
            get { return _maxSynAnt; }
            set
            {
                CheckPropertyChanged("MaxSynAnt", ref _maxSynAnt, value);
            }
        }

    }
}
